package main

import (
	"context"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"time"

	"github.com/go-redis/redis/v8"
	"gopkg.in/yaml.v2"
)

var ctx = context.Background()

func main() {
	config := flag.String("config", "config.yaml", "configuration file to load")
	flag.Parse()
	cfg, err := parse(*config)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%v\n", cfg.IsSentinel)
	fmt.Printf("%v\n", cfg.Sentinel)
	var rdb *redis.Client
	if cfg.IsSentinel {
		rdb = cfg.Sentinel.conn(ctx)
	} else {
		rdb = redis.NewClient(&redis.Options{
			Addr:     fmt.Sprintf("%s:%d", cfg.Redis.Host, cfg.Redis.Port),
			Password: "", // no password set
			DB:       0,  // use default DB
		})
	}

	fmt.Printf("\n####\nStep 1: Set key-value\n####\n")
	for _, c := range cfg.Content {
		err = rdb.Set(ctx, c.Key, c.Value, 1*time.Hour).Err()
		if err != nil {
			panic(err)
		}
		fmt.Printf("Set key-value: %s:%s\n", c.Key, c.Value)
	}
	time.Sleep(10 * time.Second)
	fmt.Printf("\n####\nStep 2: get all key-value\n####\n")
	r, err := rdb.Keys(ctx, "*").Result()
	if err != nil {
		panic(err)
	}
	for _, k := range r {
		val, err := rdb.Get(ctx, k).Result()
		if err != nil {
			panic(err)
		}
		fmt.Printf("Key-value: %s:%s\n", k, val)

	}

}

type Content struct {
	Key   string `yaml:"key"`
	Value string `yaml:"value"`
}

type Auth struct {
	Host     string `yaml:"host"`
	Port     int    `yaml:"port"`
	Username string `yaml:"username"`
	Password string `yaml:"password"`
	DB       string `yaml:"db"`
}

type Sentinel struct {
	Host             []string `yaml:"host"`
	Port             int      `yaml:"port"`
	Username         string   `yaml:"username"`
	MasterName       string   `yaml:"mastername"`
	SentinelPassword string   `yaml:"sentinelPassword"`
	Password         string   `yaml:"password"`
}

type Config struct {
	Redis      Auth       `yaml:"redis"`
	Sentinel   *Sentinel  `yaml:"sentinel"`
	IsSentinel bool       `yaml:"isSentinel"`
	Content    []*Content `yaml:"content"`
}

// Parse config.yaml to data struct
func parse(file string) (cfg *Config, err error) {
	cfg = new(Config)
	body, err := ioutil.ReadFile(file)
	if err != nil {
		return
	}
	err = yaml.Unmarshal(body, cfg)
	if err != nil {
		return
	}
	return
}

//setup Redis Sentinel
func (s *Sentinel) conn(ctx context.Context) *redis.Client {
	options := &redis.FailoverOptions{
		MasterName:       s.MasterName,
		SentinelPassword: s.SentinelPassword,
		Password:         s.Password,
	}
	for _, h := range s.Host {
		options.SentinelAddrs = append(options.SentinelAddrs, fmt.Sprintf("%s:%d", h, s.Port))
	}
	rdb := redis.NewFailoverClient(options)
	rdb.Ping(ctx)
	return rdb

}
